#!/usr/bin/env python

import sys,os,ConfigParser,commands,gobject,time,daemon
        
def Initialize():
    "initialize the program"
    
    #open config file
    global Config
    Config = ConfigParser.ConfigParser()
    ConfigFile = open("/etc/wattospm/config")
    Config.readfp(ConfigFile)
    ConfigFile.close()
    
    if Config.getboolean("config", "log"):
        logFile = open("/var/log/wattospm/log", "a")
        logFile.write("[%s] daemon started" % (time.strftime("%d/%m/%y %H:%M:%S", time.localtime()),))
        logFile.close()
    
    #if this is first run autodetect hardware and software
    if Config.getboolean("config", "first_run"):
        detectOptions()
    
    #set current power setting to unknown
    global currentSetting
    currentSetting = "0"
    
    #turn off laptop mode
    os.system("/etc/init.d/laptop-mode stop")
        
def detectOptions():
    "detect compatable hardware"
        
    #check if you have a multi-core cpu
    smp = commands.getoutput("uname -a")
    if "SMP" in smp:
        Config.set("config", "smp", "True")
        #check if you can set sched_mc_power_saving
        if os.path.exists("/sys/devices/system/cpu/sched_mc_power_savings"):
            Config.set("sched_mc", "detected", "True")
            
    #Find the root partition
    Mount = commands.getoutput("mount")
    Partitions = Mount.split("\n")
    for Partition in Partitions:
        if " / " in Partition:
            #these are the partition types I know work with these settings, if you know any more let me know
            if "reiserfs" in Partition or "ext3" in Partition:
                Config.set("dirty_background_ratio", "detected", "True")
                Config.set("dirty_ratio", "detected", "True")
                Config.set("dirty_writeback", "detected", "True")
                Config.set("journal_commit", "detected", "True")
            SplitPartition = Partition.split()
            Config.set("config", "root_partition", SplitPartition[0])
            #Strip the number off the root partition to get the drive, need to look into a more failsafe way to do this
            RootDrive = SplitPartition[0].strip("0123456789")
            Config.set("config", "root_drive", RootDrive)
     
    #Find CD-Rom Drive, this uses hal to find devices
    HalDrives = commands.getoutput("hal-find-by-capability --capability storage.cdrom").strip("\n")
    if HalDrives:
        HalInfo = commands.getoutput("hal-device " + HalDrives).split("\n")
        cdDrives = []
        for line in HalInfo:
            #the access_control.file line has the device name in it
            if "access_control.file" in line:
                AccessControl = line.split("'")
                CDRomDevice = AccessControl[1]
                cdDrives.append(CDRomDevice)
                Config.set("hal_polling", "detected", "True")
        Config.set("config", "cdrom", ",".join(cdDrives))
    
    #check for network interfaces
    ifconfig = commands.getoutput("ifconfig").split("\n")
    interfaces = []
    for line in ifconfig:
        if not line.startswith(" ") and line.split():
            interfaces.append(line.split()[0])
    Config.set("config", "interfaces", ",".join(interfaces))
    
    #Check if drive supports advanced power management
    AdvancedPM = commands.getoutput("hdparm -i " + RootDrive)
    if "AdvancedPM=yes" in AdvancedPM:
        Config.set("hdparm","detected","True") 
        
    #Check for intel sound cards
    if os.path.exists("/sys/module/snd_hda_intel"):
        Config.set("intel_sound", "detected", "True")
        
    #check for ac97 sound cards
    if os.path.exists("/sys/module/snd_ac97_codec/parameters/power_save"):
        Config.set("ac97_sound", "detected", "True")
        
    #Check if iwl wireless is in use
    wifi_dir = os.listdir("/sys/bus/pci/drivers")
    iwlDirHolder = []
    for dir in wifi_dir:
        if "iwl" in dir:
            Config.set("iwl_wifi", "detected", "True")
            iwlDirs = os.listdir("/sys/bus/pci/drivers/%s" % (dir,))
            for iwlDir in iwlDirs:
                if os.path.exists("/sys/bus/pci/drivers/%s/%s/power_level" % (dir,iwlDir)):
                    iwlDirHolder.append("%s/%s" % (dir,iwlDir))
    Config.set("iwl_wifi", "dirs", ",".join(iwlDirHolder))
            
    #Check if kernel has pcie aspm compiled in
    if os.path.exists("/sys/module/pcie_aspm"):
        Config.set("pcie_aspm", "detected", "True")
        
    # check for bluetooth devices with hciconfig, device needs to be on
    BlueInstalled = commands.getoutput("aptitude show bluez-utils | grep State")
    if ": installed" in BlueInstalled:
        devices = []
        hci = commands.getoutput("hciconfig").split("\n")
        for line in hci:
            if "hci" in line:
                Config.set("bluetooth", "detected", "True")
                devices.append(line.split(":")[0])
        Config.set("bluetooth", "devices", ",".join(devices))
        
    #Check for loaded modules
    modules = commands.getoutput("lsmod")
    #Check if webcam module is loaded, need to check if there are other modules this is the one I know dell laptops use
    camtemp = []
    for module in Config.get("webcam","modules").split(","):
        if module in modules:
            Config.set("webcam", "detected", "True")
            camtemp.append(module)
    Config.set("webcam","modules", ",".join(camtemp))
    #Check for firewire
    if "ieee1394" in modules:
        Config.set("firewire", "detected", "True")
    #Check for usb module
    if "usbcore" in modules:
        Config.set("usb", "detected", "True")
    #check for nVidia
    if "nvidia" in modules:
        Config.set("nvidia", "detected", "True")
    #check for ATI
    if "fglrx" in modules:
        Config.set("ati", "detected", "True")
        
    #Check if tracker is installed
    TrackerInstalled = commands.getoutput("aptitude show tracker | grep State")
    if ": installed" in TrackerInstalled:
        Config.set("tracker", "detected", "True")
        
    #Check if xbacklight is installed
    xbacklightInstalled = commands.getoutput("aptitude show xbacklight | grep State")
    if ": installed" in xbacklightInstalled:
        Config.set("xbacklight", "detected", "True")
        
    #Check for sata hosts
    sata_dir = os.listdir("/sys/class/scsi_host")
    sata_hosts = []
    #not sure if this works someone without sata will have to test it for me
    if sata_dir:
        for host in sata_dir:
            if os.path.exists("/sys/class/scsi_host/%s/link_power_management_policy" % (host,)):
                Config.set("sata", "detected", "True")
                sata_hosts.append(host)
    Config.set("sata", "hosts", ",".join(sata_hosts))
    
    #check for acpi thermal management
    thermal = os.listdir("/proc/acpi/thermal_zone")
    zones = []
    for zone in thermal:
        if os.path.exists("/proc/acpi/thermal_zone/%s/polling_frequency" % (zone,)):
            Config.set("acpi_therm", "detected", "True")
            zones.append(zone)
    Config.set("acpi_therm", "dirs", ",".join(zones))
    
    #Check for nmi watchdog
    if os.path.exists("/proc/sys/kernel/nmi_watchdog"):
        Config.set("nmi_watchdog", "detected", "True")
        
    Config.set("config", "first_run", "False")
    
    #check if machine has a battery
    batteries = os.listdir("/proc/acpi/battery")
    if batteries:
        Config.set("config", "activation", "auto")
    else:
        Config.set("config", "activation", "manual")
    
    #write config to disk
    Config.write(open("/etc/wattospm/config","w"))
    
def change_power_mode(setting):
    "change power mode"
    
    global currentSetting
    
    if setting == "saving":
        currentSetting = "power_saving"
        Config.set("config", "current_mode", "power_saving")
        configSetting = "saving_setting"
    else:
        currentSetting = "performance"
        Config.set("config", "current_mode", "performance")
        configSetting = "performance_setting"
    
    log = []
    #set hdparm settings
    if Config.getboolean("hdparm", "detected") and Config.getboolean("hdparm", "enabled"):
        hdparm = commands.getoutput("hdparm %s %s" % (Config.get("hdparm", configSetting), Config.get("config", "root_drive")))
        log.append("hdparm: %s" % (hdparm,))
        
    #change journal commit
    if Config.getboolean("journal_commit", "detected") and Config.getboolean("journal_commit", "enabled"):
        journal = commands.getoutput("mount -o remount,commit=%s /" % (Config.get("journal_commit",configSetting),))
        log.append("Journal Commit: %s" % (journal,))
        
    #set intel iwl wifi power
    if Config.getboolean("iwl_wifi", "detected") and Config.getboolean("iwl_wifi", "enabled"):
        dirs = Config.get("iwl_wifi", "dirs").split(",")
        iwlOutput = []
        for dir in dirs:
            iwlOutput.append(commands.getoutput("echo %s > /sys/bus/pci/drivers/%s/power_level" % (Config.get("iwl_wifi", configSetting), dir)))
        log.append("iwl wifi: %s" % ("\n".join(iwlOutput),))
        
    #set intel ipw wifi power
    if Config.getboolean("ipw_wifi", "detected") and Config.getboolean("ipw_wifi", "enabled"):
        ipw = commands.getoutput("iwpriv %s set_power %s" % (Config.get("ipw_wifi", "interface"), Config.get("ipw_wifi", configSetting)))
        log.append("ipw wifi: %s" % (ipw,))
            
    #set dirty ratio
    if Config.getboolean("dirty_ratio", "detected") and Config.getboolean("dirty_ratio", "enabled"):
        dirty = commands.getoutput("echo %s > /proc/sys/vm/dirty_ratio" % (Config.get("dirty_ratio", configSetting),))
        log.append("dirty ratio: %s" % (dirty,))
        
    #set dirty background ratio
    if Config.getboolean("dirty_background_ratio", "detected") and Config.getboolean("dirty_background_ratio", "enabled"):
        dirtyBack = commands.getoutput("echo %s > /proc/sys/vm/dirty_background_ratio" % (Config.get("dirty_background_ratio", configSetting),))
        log.append("dirty background ratio: %s" % (dirtyBack,))
        
    #set dirty writeback
    if Config.getboolean("dirty_writeback", "detected") and Config.getboolean("dirty_writeback", "enabled"):
        dirtyWrite = commands.getoutput("echo %s > /proc/sys/vm/dirty_writeback_centisecs" % (Config.get("dirty_writeback", configSetting),))
        log.append("dirty writeback: %s" % (dirtyWrite,))
        
    #set readahead
    if Config.getboolean("readahead", "detected") and Config.getboolean("readahead", "enabled"):
        readahead = commands.getoutput("blockdev --setra %s %s" % (Config.get("readahead", configSetting),Config.get("config","root_drive")))
        log.append("readahead: %s" % (readahead,))
        
    #set intel sound power mode
    if Config.getboolean("intel_sound", "detected") and Config.getboolean("intel_sound", "enabled"): 
        iSound = commands.getoutput("echo %s > /sys/module/snd_hda_intel/parameters/power_save" % (Config.get("intel_sound", configSetting),))
        log.append("intel sound: %s" % (iSound,))
        
    #set ac97_sound power mode
    if Config.getboolean("ac97_sound", "detected") and Config.getboolean("ac97_sound", "enabled"): 
        ac97 = commands.getoutput("echo %s > /sys/module/snd_ac97_codec/parameters/power_save" % (Config.get("ac97_sound", configSetting),))
        os.system("echo 1 > /dev/dsp")
        log.append("ac97 sound: %s" % (ac97,))
        
    #set sata power management policy
    if Config.getboolean("sata", "detected") and Config.getboolean("sata", "enabled"):  
        sata_hosts = Config.get("sata", "hosts").strip("\n").split(",")
        sataLog = []
        for host in sata_hosts:
            sataLog.append(commands.getoutput("echo %s > /sys/class/scsi_host/%s/link_power_management_policy" % (Config.get("sata", configSetting), host)))
        log.append("sata link power: %s" % ("\n".join(sataLog),))
            
    #set pcie aspm power policy
    if Config.getboolean("pcie_aspm", "detected") and Config.getboolean("pcie_aspm", "enabled"): 
        pcie = commands.getoutput("echo %s > /sys/module/pcie_aspm/parameters/policy" % (Config.get("pcie_aspm", configSetting),))
        log.append("pcie aspm: %s" % (pcie,))
        
    #set drive polling
    if Config.getboolean("hal_polling", "detected") and Config.getboolean("hal_polling", "enabled"):
        hal_drives = Config.get("config", "cdrom").strip("\n").split(",")
        halLog = []
        for drive in hal_drives:
            if setting == "saving":
                halLog.append(commands.getoutput("hal-disable-polling --device %s" %(drive,)))
            else:
                halLog.append(commands.getoutput("hal-disable-polling --device %s --enable-polling" %(drive,)))
        log.append("hal drive polling: %s" % ("\n".join(halLog),))        
    #set multi-core scheduling
    if Config.getboolean("sched_mc", "detected") and Config.getboolean("sched_mc", "enabled"):
        mc = commands.getoutput("echo %s > /sys/devices/system/cpu/sched_mc_power_savings" % (Config.get("sched_mc", configSetting),)) 
        log.append("multi-core scheduling: %s" % (mc,))
        
    #kill or start tracker   
    if Config.getboolean("tracker", "detected") and Config.getboolean("tracker", "enabled"):
        if setting == "saving":
            tracker = commands.getoutput("killall trackerd")
        else:
            tracker = commands.getoutput("trackerd &")
        log.append("tracker: %s" % (tracker,))
        
    #change window manager
    if Config.getboolean("window_manager", "detected") and Config.getboolean("window_manager", "enabled"):
        wm = commands.getoutput("%s --replace &" % (Config.get("window_manager", configSetting),))
        log.append("window manager: %s" % (wm,))
        
    #set ati videocard power settings
    if Config.getboolean("ati", "detected") and Config.getboolean("ati", "enabled"):    
        ati = commands.getoutput("su %s -c 'aticonfig --set-powerstate %s'" % (Config.get("config", "username"), Config.get("ati", configSetting)))
        log.append("ati video: %s" % (ati,))
        
    #set nvidia videocard power settings
    if Config.getboolean("nvidia", "detected") and Config.getboolean("nvidia", "enabled"):
        sync_to_vblank, slide_duration = Config.get("nvidia", configSetting).split(",")
        dbus = commands.getoutput('grep -v "^#" /home/%s/.dbus/session-bus/`cat /var/lib/dbus/machine-id`-0' % (Config.get("config","username"),)).split("\n")
        nv1 = commands.getoutput("sudo -u %s env %s gconftool-2 --type boolean --set /apps/compiz/general/screen0/options/sync_to_vblank %s" % (Config.get("config", "username"), dbus[0], sync_to_vblank))
        nv2 = commands.getoutput("sudo -u %s env %s gconftool-2 --type float --set /apps/compiz/plugins/wall/allscreens/options/slide_duration %s" % (Config.get("config", "username"), dbus[0], slide_duration))
        log.append("nvidia compiz vblank: %s" % (nv1,))
        log.append("nvidia compiz wall: %s" % (nv2,))
        
    #enable/disable bluetooth
    if Config.getboolean("bluetooth", "detected") and Config.getboolean("bluetooth", "enabled"): 
        blueLog = []
        if setting == "saving":
            devices = Config.get("bluetooth", "devices",).split(",")
            for device in devices:
                blueLog.append(commands.getoutput("hciconfig %s down" % (device,)))
            blueLog.append(commands.getoutput("/etc/init.d/bluetooth stop"))
            time.sleep(1)
            for module in Config.get("bluetooth","modules").split(","):
                blueLog.append(commands.getoutput("rmmod %s" % (module,)))
        else:
            for module in Config.get("bluetooth","modules").split(","):
                blueLog.append(commands.getoutput("modprobe %s" % (module,)))
            blueLog.append(commands.getoutput("/etc/init.d/bluetooth start"))
        log.append("bluetooth: %s" % ("\n".join(blueLog),))
        
    #enable/disable usb
    if Config.getboolean("usb", "detected") and Config.getboolean("usb", "enabled"): 
        usbLog = []
        if setting == "saving":            
            for module in Config.get("usb", "modules").split(","):
               usbLog.append(commands.getoutput("rmmod %s" % (module,)))
        else:
            for module in Config.get("usb", "modules").split(","):
                usbLog.append(commands.getoutput("modprobe %s" % (module,)))
        log.append("usb: %s" % ("\n".join(usbLog),))
                
    #enable/disable webcam
    if Config.getboolean("webcam", "detected") and Config.getboolean("webcam", "enabled"): 
        camLog = []
        if setting == "saving":            
            for module in Config.get("webcam", "modules").split(","):
                camLog.append(commands.getoutput("rmmod %s" % (module,)))
        else:
            for module in Config.get("webcam", "modules").split(","):
                camLog.append(commands.getoutput("modprobe %s" % (module,)))
        log.append("webcam: %s" % ("\n".join(camLog),))     
        
    #enable/disable firewire
    if Config.getboolean("firewire", "detected") and Config.getboolean("firewire", "enabled"): 
        fireLog = []
        if setting == "saving":            
            for module in Config.get("firewire", "modules").split(","):
                fireLog.append(commands.getoutput("rmmod %s" % (module,)))
        else:
            for module in Config.get("firewire", "modules").split(","):
                fireLog.append(commands.getoutput("modprobe %s" % (module,)))
        log.append("firewire: %s" % ("\n".join(fireLog),))   
        
    #set backlight
    if Config.getboolean("xbacklight", "detected") and Config.getboolean("xbacklight", "enabled"):
        os.environ["DISPLAY"] = Config.get("config", "display") 
        backlight = commands.getoutput("xbacklight -set %s" % (Config.get("xbacklight", configSetting),))
        os.environ.pop("DISPLAY")
        log.append("xbacklight: %s" % (backlight,))
        
    #set acpi thermal polling frequency
    if Config.getboolean("acpi_therm", "detected") and Config.getboolean("acpi_therm", "enabled"):
        thermLog = []
        for zone in Config.get("acpi_therm", "dirs").split(","):
            thermLog.append(commands.getoutput("echo %s > /proc/acpi/thermal_zone/%s/polling_frequency" % (Config.get("acpi_therm", configSetting),zone)))
        log.append("thermal polling: %s" % ("\n".join(thermLog),))

    #turn nmi_watchdog on and off
    if Config.getboolean("nmi_watchdog", "detected") and Config.getboolean("nmi_watchdog", "enabled"):
        nmi = commands.getoutput("echo %s > /proc/sys/kernel/nmi_watchdog" % (Config.get("nmi_watchdog", configSetting),))
        log.append("nmi watchdog: %s" % (nmi,))
    
    #log
    if Config.getboolean("config", "log"):
        logFile = open("/var/log/wattospm/log", "a")
        logFile.write("\n[%s]\n" % (time.strftime("%d/%m/%y %H:%M:%S", time.localtime()),))
        logFile.write("\n".join(log))
        logFile.close()
        
    #write config to disk
    Config.write(open("/etc/wattospm/config","w"))
    
def on_ac_power():
    "check if your on ac power"
    
    batteries = os.listdir("/proc/acpi/battery")
    if batteries:
        #just checks the first detected battery
        PowerSetting = open("/proc/acpi/battery/%s/state" % (batteries[0],))
        for line in PowerSetting:
            if "charging" in line:
                if "discharging" in line:
                    return False
                else:
                    return True

def AutoSet():
    "set performance and powersaving options automatically"
    
    global currentSetting
    
    #open config file
    global Config
    Config = ConfigParser.ConfigParser()
    ConfigFile = open("/etc/wattospm/config")
    Config.readfp(ConfigFile)
    ConfigFile.close()
    
    if Config.getboolean("config", "first_run"):
        detectOptions()
    
    #if set to manual mode check if the current mode is different than the requested mode
    if Config.get("config", "activation") == "manual":
        if not Config.get("config", "requested_mode") == currentSetting:
            change_power_mode(Config.get("config", "requested_mode"))
    
    #if set to auto check if plugged in and change mode accordingly
    if Config.get("config", "activation") == "auto":
        if on_ac_power():
            if not currentSetting == "performance":
                change_power_mode("performance")
        else:
            if not currentSetting == "power_saving":
                change_power_mode("saving")
                
    gobject.timeout_add(1000, AutoSet)
        
if __name__ == "__main__":
    "main loop"
    
    #daemonize this process
    daemon.createDaemon()
    
    #create pid file
    pid = os.getpid()
    if os.path.exists("/var/run/wattospm-daemon.pid"):
        os.remove("/var/run/wattospm-daemon.pid")
    os.system("touch /var/run/wattospm-daemon.pid")
    os.system("echo %i > /var/run/wattospm-daemon.pid" % (pid,))

    #initialize
    Initialize()
    
    AutoSet()
    
    loop = gobject.MainLoop()
    loop.run()
